//
// Created by lenovo on 2023/11/30.
//

#include "qjsonmesh.h"
#include "nlohmann/json.hpp"
#include <fstream>;
#include <iostream>
#include "qlinemesh.h"
QJsonMesh::QJsonMesh(std::string jsonfile, Qt3DCore::QNode* root)
	: QGeometryRenderer(root)
{
	// 这里是构造2个三角形的例子
	//vertices.append(QVector3D{-10, -10, 0});
	//vertices.append(QVector3D{ -10, 10, 0});
	//vertices.append(QVector3D{10, -10, 0});
	//vertices.append(QVector3D{10, 10, 0});
	// 注意顶点索引的顺序应该按照逆时针
	//indices.append(0);
	//indices.append(2);
	//indices.append(1);
	//indices.append(0);
	//indices.append(2);
	//indices.append(3);
	loadJsonMesh(jsonfile);
	// 构造QGeometry
	geometry = new Qt3DRender::QGeometry(root);
	// 构造顶点数组
	QByteArray bufferBytes;
    bufferBytes.resize(3 * vertices.size() * sizeof(float));
    auto *positions = reinterpret_cast<float*>(bufferBytes.data());
	for (int n = vertices.size(), i = 0; i < n; ++i)
	{
		*positions++ = vertices[i].x();
		*positions++ = vertices[i].y();
		*positions++ = vertices[i].z();
	}
    m_vertexBuffer = new Qt3DRender::QBuffer(geometry);
    m_vertexBuffer->setData(bufferBytes);
	// 设置位置属性
    m_positionAttribute = new Qt3DRender::QAttribute(geometry);
    m_positionAttribute->setName(Qt3DRender::QAttribute::defaultPositionAttributeName());
	// 数据类型
    m_positionAttribute->setVertexBaseType(Qt3DRender::QAttribute::Float);
	// Holds the data size, it can only be 1 to 4 units (scalars and vectors),
	// 9 units (3x3 matrices) or 16 units (4x4 matrices).
    m_positionAttribute->setVertexSize(3);
    m_positionAttribute->setAttributeType(Qt3DRender::QAttribute::VertexAttribute);
    m_positionAttribute->setBuffer(m_vertexBuffer);
	// VertexAttribute: used to define data to be read on a per vertex basis
	// IndexAttribute:  used to define vertex indices when indexed draw calls are to be used
    m_positionAttribute->setByteStride(3 * sizeof(float));
	// 顶点个数
    m_positionAttribute->setCount(vertices.size());
    geometry->addAttribute(m_positionAttribute);
	// 构造索引数组
    QByteArray indexBytes;
	indexBytes.resize(indices.size() * sizeof(unsigned int)); // start to end
	memcpy(indexBytes.data(), indices.data(), indices.size() * sizeof(unsigned int));
    m_indexBuffer = new Qt3DRender::QBuffer(geometry);
    m_indexBuffer->setData(indexBytes);
	// 设置索引属性
	m_indexAttribute = new Qt3DRender::QAttribute(geometry);
	m_indexAttribute->setVertexBaseType(Qt3DRender::QAttribute::UnsignedInt);
	m_indexAttribute->setAttributeType(Qt3DRender::QAttribute::IndexAttribute);
	m_indexAttribute->setVertexSize(1);
	m_indexAttribute->setBuffer(m_indexBuffer);
	m_indexAttribute->setByteStride(1 * sizeof(unsigned int));
	m_indexAttribute->setCount(indices.size());
	geometry->addAttribute(m_indexAttribute);
	// 设置图元
	setPrimitiveType(Qt3DRender::QGeometryRenderer::Triangles);
	setGeometry(geometry);

	lineMaterial = new Qt3DExtras::QPhongMaterial();
	lineMaterial->setAmbient(Qt::black);
	lineEntity = new Qt3DCore::QEntity(root);
	line_mesh  = new QLineMesh(vertices,lineindices, root,Qt3DRender::QGeometryRenderer::Lines);
	lineEntity->addComponent(line_mesh);
	lineEntity->addComponent(lineMaterial);
}


QJsonMesh::~QJsonMesh()
{
	delete m_positionAttribute;
	delete m_indexAttribute;
	delete m_vertexBuffer;
	delete m_indexBuffer;
	delete geometry;
}

void QJsonMesh::loadJsonMesh(const std::string& jsonfile) {
	std::ifstream f(jsonfile);
	nlohmann::json data = nlohmann::json::parse(f);
	nlohmann::json vnodes = data["Vertices"];
	for(auto vnode : vnodes)
	{
		QVector3D vertice{vnode[0].get<float>(),vnode[1].get<float>(),vnode[2].get<float>()};
		vertices.append(vertice);
	}
	nlohmann::json fnodes = data["Faces"];
	for(const auto& fnode : fnodes)
	{
		int i1 = fnode[0].get<int>() - 1;
		int i2 = fnode[1].get<int>() - 1;
		int i3 = fnode[2].get<int>() - 1;
		QVector3D a = vertices[i1];
		QVector3D b = vertices[i2];
		QVector3D c = vertices[i3];
		QVector3D ab = b-a;
		QVector3D bc = c-b;
		QVector3D n1 = QVector3D::crossProduct(ab, bc);
		QVector3D n2 = (a+b+c)/3.0;
		// 如果法向量朝里则需要调换顶点顺序
		if(QVector3D::dotProduct(n1,n2) < 0) {
			indices.append(i1);
			indices.append(i3);
			indices.append(i2);
		}else {
			indices.append(i1);
			indices.append(i2);
			indices.append(i3);
		}
		lineindices.append(i1);
		lineindices.append(i2);
		lineindices.append(i2);
		lineindices.append(i3);
		lineindices.append(i1);
		lineindices.append(i3);

	}
}


